﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MathNet.Numerics.LinearAlgebra.Double;
using MoveView.Model;

namespace MoveView.MyMath
{
    public class DoubleDenseVector3D
        : DenseVector
    {
        public DoubleDenseVector3D(MathNet.Numerics.LinearAlgebra.Generic.Vector<double> copy)
            : base(copy.ToArray())
        { }

        public DoubleDenseVector3D(double component1, double component2, double component3)
            : base(new double[]{component1, component2, component3})
        { }

        public DoubleDenseVector3D(double[] components)
            : base(components)
        {
            if (components.Length != 3)
                throw new Exception("Vector must have exactly 3 components. (3 elements in the array given to constructor)");
        }

        public DoubleDenseVector3D() : base(3)
        { }

        public DoubleDenseVector3D CrossProduct(DoubleDenseVector3D other)
        {
            return DoubleDenseVector3D.CrossProduct(this, other);
        }

        public static DoubleDenseVector3D CrossProduct(DoubleDenseVector3D left, DoubleDenseVector3D right)
        {
            if ((left.Count != 3 || right.Count != 3))
            {
                string message = "Vectors must have a length of 3.";
                throw new Exception(message);
            }
            DoubleDenseVector3D result = new DoubleDenseVector3D();
            result[0] = left[1] * right[2] - left[2] * right[1];
            result[1] = -left[0] * right[2] + left[2] * right[0];
            result[2] = left[0] * right[1] - left[1] * right[0];

            return result;
        }

        public static XYZ CrossProduct(XYZ left, XYZ right)
        {
            XYZ result = new XYZ();
            result.x = left.y * right.z - left.z * right.y;
            result.y = -left.x * right.z + left.z * right.x;
            result.z = left.x * right.y - left.y * right.x;

            return result;
        }

        public DoubleDenseVector3D GetPerpendicularVector()
        {
            DoubleDenseVector3D temp = this.CrossProduct(new DoubleDenseVector3D(new double[]{1,0,0}));
            if (temp.DotProduct(temp) < 0.3)
                temp = this.CrossProduct(new DoubleDenseVector3D(new double[] { 0, 1, 0 }));
            return temp as DoubleDenseVector3D;
        }


        
        public DoubleDenseVector3D Normalize()
        {
            DoubleDenseVector3D temp = new DoubleDenseVector3D();
            temp[0] = this[0] / this.Magnitude;
            temp[1] = this[1] / this.Magnitude;
            temp[2] = this[2] / this.Magnitude;
            return temp;
        }

        public static XYZ Normalize(XYZ input)
        {
            double magnitude = Math.Sqrt(input.x * input.x + input.y * input.y + input.z * input.z);
            XYZ result = new XYZ();
            result.x = input.x / magnitude;
            result.y = input.y / magnitude;
            result.z = input.z / magnitude;
            return result;
        }

        public double Magnitude {
            get
            {
                return Math.Sqrt(this[0] * this[0] + this[1] * this[1] + this[2] * this[2]);
            }
            set
            {
                DoubleDenseVector3D unitVector = new DoubleDenseVector3D(this.Divide(Magnitude));
                DoubleDenseVector3D modVector = new DoubleDenseVector3D(unitVector.Multiply(value));
                this[0] = modVector[0];
                this[1] = modVector[1];
                this[2] = modVector[2];
            }
        }

    }
}
